package com.applet.orders.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.applet.addressbook.service.AddressBookService;
import com.applet.constant.MessageConstant;
import com.applet.context.AlibabaTTL;
import com.applet.dto.OrdersPageQueryDTO;
import com.applet.dto.OrdersPaymentDTO;
import com.applet.dto.OrdersSubmitDTO;
import com.applet.entity.*;
import com.applet.exception.AddressBookBusinessException;
import com.applet.exception.OrderBusinessException;
import com.applet.exception.ShoppingCartBusinessException;
import com.applet.orderdetail.service.OrderDetailService;
import com.applet.orders.mapper.OrderMapper;
import com.applet.orders.service.OrderService;
import com.applet.properties.WeChatProperties;
import com.applet.result.PageResult;
import com.applet.shoppingcart.service.ShoppingCartService;
import com.applet.user.service.UserService;
import com.applet.utils.BaiduGeoUtil;
import com.applet.utils.HttpClientUtil;
import com.applet.utils.WeChatPayUtil;
import com.applet.vo.OrderPaymentVO;
import com.applet.vo.OrderSubmitVO;
import com.applet.vo.OrderVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单管理 serviceImpl
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {


    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailService orderDetailService;

    @Resource
    private AddressBookService addressBookService;

    @Resource
    private ShoppingCartService shoppingCartService;

    @Resource
    private UserService userService;

    @Resource
    private WeChatPayUtil weChatPayUtil;

    @Resource
    private WeChatProperties weChatProperties;


    @Resource
    private BaiduGeoUtil baiduGeoUtil;


    // 商家后台来单提醒服务地址
    @Value("${shop.shopPaySuccessUrl}")
    private static String shopPaySuccessUrl;

    // 商家后台用户催单服务地址
    @Value("${shop.shopReminderUrl}")
    private static String shopReminderUrl;



    /**
     * 订单管理
     *         用户下单
     * @param ordersSubmitDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {

        // 数据校验(地址簿为空 / 购物车为空 / )
        AddressBook addressBook = addressBookService.selectAddressBookById(ordersSubmitDTO.getAddressBookId());
        if(Objects.isNull(addressBook)){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        // 百度地图距离校验 是否超出配送距离
        baiduGeoUtil.chooseOutOfRang(addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail());

        // 用户id
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());

        // 查询购物车数据
        List<ShoppingCart> shoppingCartList = shoppingCartService.selectUserShopCart(userId);
        if(CollectionUtils.isEmpty(shoppingCartList)){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }


        //封装收货地址
        String address = addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail();
        address = address.replace("null", "");

        // 1.订单表插入一条数据
        Orders orders = JSON.parseObject(JSON.toJSONString(ordersSubmitDTO, SerializerFeature.WriteMapNullValue), Orders.class);
        orders.setNumber(UUID.randomUUID().toString().replace("-",""));        //订单号
        orders.setStatus(Orders.PENDING_PAYMENT);        //订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        orders.setUserId(userId);                        //下单用户id
        orders.setOrderTime(LocalDateTime.now());        //下单时间
        //orders.setCheckoutTime();                      //结账时间
        orders.setPayStatus(Orders.UN_PAID);             //支付状态 0未支付 1已支付 2退款
        orders.setUserName(addressBook.getConsignee());  //用户名
        orders.setPhone(addressBook.getPhone());         //手机号
        orders.setAddress(address);                      //地址
        orders.setConsignee(addressBook.getConsignee()); //收货人
        //orders.setCancelReason();    //订单取消原因
        //orders.setRejectionReason(); //订单拒绝原因
        //orders.setCancelTime();      //订单取消时间
        //orders.setDeliveryTime();    //送达时间

        Integer orderCount = orderMapper.insert(orders);

        // 2.订单明细表插入多条数据
        orderDetailService.addOrderDetailList(shoppingCartList, orders.getId());

        // 3.清空购物车数据
        shoppingCartService.deleteUserShopCart(userId);

        // 4.封装返回值vo
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder().id(orders.getId()).orderNumber(orders.getNumber()).orderAmount(orders.getAmount()).orderTime(orders.getOrderTime()).build();
        return orderSubmitVO;
    }

    //计算总金额
    public Double sumAmount(List<ShoppingCart> shoppingCartList){
        Double ordersAmount = new Double("0.00");
        for (ShoppingCart shoppingCart : shoppingCartList) {
            // 数量
            Integer number = shoppingCart.getNumber();
            // 单价
            BigDecimal amount = shoppingCart.getAmount();
            // 数量转为string
            String numString = String.valueOf(number);
            // 单价转为string
            String amountString = String.valueOf(amount);
            // BigDecimal
            BigDecimal numDecimal = new BigDecimal(numString);
            BigDecimal amountDecimal = new BigDecimal(amountString);
            // 乘法
            BigDecimal result = numDecimal.multiply(amountDecimal);
            //
            ordersAmount += result.doubleValue();
        }
        return ordersAmount;
    }




    /**
     * 订单管理
     *         微信生成预支付订单，返回小程序调用微信服务需要的数据 wx.requestPayment({...})
     * @param ordersPaymentDTO
     */
    @Override
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) {
        // 1.用户信息
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());
        User user = userService.getById(userId);

        // 2.订单信息
        String orderNumber = ordersPaymentDTO.getOrderNumber(); //订单号
        Orders paramsOrders = Orders.builder().userId(userId).number(orderNumber).build();
        Orders orders = orderMapper.getOrderByUserIdAndNumber(paramsOrders);

        // 3.设置支付方式
        orders.setPayMethod(ordersPaymentDTO.getPayMethod());
        Integer count = orderMapper.updateById(orders);

        // 4.调用微信支付接口，生成预支付单
        JSONObject dataObject = new JSONObject();
//        try {
//            dataObject = weChatPayUtil.pay(orders.getNumber(), orders.getAmount(), "外卖下单", user.getOpenid());
//        } catch (Exception e) {
//            log.info("用户id: {},订单号: {},调用微信服务生成预支付订单号失败", userId, orders.getNumber());
//            throw new OrderBusinessException(MessageConstant.ORDER_PAYMENT_ERROR);
//        }
//
//        // 5.校验结果
//        if(StringUtils.hasLength(dataObject.getString("code")) && dataObject.getString("code").equals("ORDERPAID")){
//            //重复下单
//            throw new OrderBusinessException(MessageConstant.ORDER_DUPLICATE);
//        }

        // 6.封装返回结果
        OrderPaymentVO orderPaymentVO = dataObject.toJavaObject(OrderPaymentVO.class);
        //orderPaymentVO.setPackageStr(dataObject.getString("package"));

        return orderPaymentVO;
    }



    /**
     * 订单管理
     *        支付成功后 结果处理
     */
    @Override
    public void paymentSuccessNotify(HttpServletRequest request, HttpServletResponse response) {
        // 支付成功后，微信返回数据结息
        String plainText = parseWeChatPayment(request);


        // 3.格式化解析后的文本 取值
        JSONObject jsonObject = JSON.parseObject(plainText);
        // 本系统生成的订单号
        String outTradeNo = jsonObject.getString("out_trade_no");
        // 微信支付交易号
        String transactionId = jsonObject.getString("transaction_id");

        log.info("系统订单号: {}", outTradeNo);
        log.info("微信支付交易号: {}", transactionId);

        // 4.根据订单号查询订单
        Orders orders = orderMapper.selectOrderByNumber(outTradeNo);

        // 5.修改订单表状态
        Orders newOlder = Orders.builder().id(orders.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build();
        orderMapper.updateById(newOlder);
        log.info("订单号: {},微信支付交易号: {},支付成功!", outTradeNo, transactionId);

        //TODO WebSocket服务
        /** 调用商户管理端后台，发送下单支付成功通知  **/
        Map<String,String> map = new HashMap<>();
        map.put("type", "1");                           // 1表示来单提醒  2表示客户催单
        map.put("orderId", orders.getId().toString());  // 订单id
        map.put("content", "订单号：" + outTradeNo);      // 订单号
        // 返回结果
        String resultStr = null;
        try {
            // 发送HTTP请求
            resultStr = HttpClientUtil.doPostJsonHasParamsResponseJson(shopPaySuccessUrl, map);
            log.info("调用商家后台【来单提醒服务】,响应结果:" + resultStr);
            if(StringUtils.hasLength(resultStr)){
                JSONObject data = JSON.parseObject(resultStr);
                if(Objects.nonNull(data) && data.getInteger("code") == 1){
                    //       {"code":1,"msg":null,"data":null}
                    log.info("订单id: {},订单号:{},调用商家后台【来单提醒服务】成功", orders.getId(), outTradeNo);
                }
            }
        } catch (Exception e) {
            log.info("调用商家后台【来单提醒服务】,抛出异常:", e.getMessage());
            e.printStackTrace();
        }

        // 6.给微信响应 告知微信我们后台服务接收到结果了
        response.setStatus(HttpStatus.SC_OK);  //状态码
        response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("code", "SUCCESS");
        resultMap.put("msg", "SUCCESS");
        try {
            response.getOutputStream().write(JSONUtils.toJSONString(resultMap).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (IOException e) {
            log.info(outTradeNo + "--WeChatPayment微信支付成功，响应订单状态修改成功信息给微信服务失败--");
            e.printStackTrace();
        }
    }

    // 解析微信支付成功后返回的结果
    private String parseWeChatPayment(HttpServletRequest request) {
        String resultStr = null;

        try {
            // 1.读取数据
            request.setCharacterEncoding(Consts.UTF_8.toString());
            BufferedReader reader = request.getReader();

            StringBuilder stringBuilder = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null){
                if(stringBuilder.length() > 0){
                    stringBuilder.append("\n");
                }
                stringBuilder.append(line);
            }
            String result = stringBuilder.toString();
            log.info("WeChatPay微信预支付成功，返回: {}", reader);

            // 2.数据解密
            JSONObject data = JSONObject.parseObject(result);
            JSONObject resource = data.getJSONObject("resource");

            String ciphertext = resource.getString("ciphertext");
            String nonce = resource.getString("nonce");
            String associatedData = resource.getString("associated_data");

            AesUtil aesUtil = new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8));
            // 密文解密
            String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
            log.info("解密后的文本: {}", plainText);

            resultStr = plainText;

        } catch (Exception e) {
            log.info("--WeChatPayment微信支付成功后返回结果解析异常--");
            e.printStackTrace();
        }
        return resultStr;
    }



    /**
     * 订单管理
     *        历史订单分页条件查询
     * @param pageNum
     * @param pageSize
     * @param status
     */
    @Override
    public PageResult queryPage(Integer pageNum, Integer pageSize, Integer status) {
        // 1.PageHelper设置分页参数 ， 排序参数
        PageHelper.startPage(pageNum, pageSize, "order_time desc");

        // 2.当前用户id
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());

        // 3.封装查询参数
        OrdersPageQueryDTO ordersPageQueryDTO = OrdersPageQueryDTO.builder().userId(userId).status(status).build();

        // 4.封装订单集合，封装为PageHelper的集合
        Page<Orders> page = orderMapper.selectPage(ordersPageQueryDTO);

        // 5.创建List<OrderVO>集合 收集数据，如果没有，则为[],也可以返回给前端 防止最后return报错
        List<OrderVO> orderVOList = new ArrayList<>();

        // 6.判断是否有订单数据     将Orders转为OrderVO
        if (Objects.nonNull(page) && page.getTotal() > 0) {
            orderVOList = page.getResult().stream().map(orders -> {
                // 对象拷贝
                OrderVO orderVO = JSON.parseObject(JSON.toJSONString(orders, SerializerFeature.WriteMapNullValue), OrderVO.class);
                // 根据orderId 查询订单明细列表
                List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailListByOrderId(orders.getId());
                // 判断 封装数据
                if ( !CollectionUtils.isEmpty(orderDetailList) ) {
                    // 订单明细集合
                    orderVO.setOrderDetailList(orderDetailList);
                    // 订单中，菜品名称和数量信息   可乐*3;啤酒*2;......
                    String orderDishes = orderDetailList.stream().map(orderDetail -> orderDetail.getName() + "*" + orderDetail.getNumber()).collect(Collectors.joining(";"));
                    orderVO.setOrderDishes(orderDishes);
                }
                return orderVO;
            }).collect(Collectors.toList());
        }
        return new PageResult(page.getTotal(), orderVOList);
    }



    /**
     * 订单管理
     *        根据id查询订单和明细
     * @param id
     */
    @Override
    public OrderVO getById(Long id) {
        // 1.查订单
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());
        Orders paramsOrder = Orders.builder().id(id).userId(userId).build();
        Orders orders = orderMapper.getOrderByIdAndUserId(paramsOrder);

        // 2.查明细
        List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailListByOrderId(orders.getId());

        // 3.封装返回数据
        OrderVO orderVO = JSON.parseObject(JSON.toJSONString(orders, SerializerFeature.WriteMapNullValue), OrderVO.class);
        if( !CollectionUtils.isEmpty(orderDetailList) ){
            // 订单明细
            orderVO.setOrderDetailList(orderDetailList);
            // 订单中，菜品名称和数量信息   可乐*3;啤酒*2;......
            String orderDishes = orderDetailList.stream().map(orderDetail -> orderDetail.getName() + "*" + orderDetail.getNumber()).collect(Collectors.joining(";"));
            orderVO.setOrderDishes(orderDishes);
        }

        return orderVO;
    }



    /**
     * 订单管理
     *         用户取消订单
     * - 待支付和待接单状态下，用户可直接取消订单
     * - 商家已接单状态下，用户取消订单需电话沟通商家
     * - 派送中状态下，用户取消订单需电话沟通商家
     * - 如果在待接单状态下取消订单，需要给用户退款
     * - 取消订单后需要将订单状态修改为“已取消”
     * @param id
     */
    @Override
    public void userCancelOrder(Long id) {
        // 1.查询订单
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());
        Orders paramsOrder = Orders.builder().id(id).userId(userId).build();
        Orders orders = orderMapper.getOrderByIdAndUserId(paramsOrder);

        // 2.非空判断
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        // 3.判断订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
        if(orders.getStatus() > 2){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        // 创建修改订单对象
        Orders updateOrder = new Orders();
        updateOrder.setId(orders.getId());

        // 4.订单处于付款成功，待接单状态时，需要退款                 用户退款使用的订单状态
        if(orders.getStatus() == Orders.TO_BE_CONFIRMED) {
            try {
                String refund = weChatPayUtil.refund(
                        orders.getNumber(), //商户订单号
                        orders.getNumber(), //商户退款单号
                        orders.getAmount(), //退款金额，单位 元
                        orders.getAmount()  //原订单金额
                );
                log.info("用户id: {},订单id: {},订单号: {},取消订单,WeChatPay退款结果: {}",userId, orders.getId(), orders.getNumber(), refund);

                //修改为支付状态 退款 payStatus=2
                updateOrder.setPayStatus(Orders.REFUND);
            } catch (Exception e) {
                log.info("用户id: {},订单号: {},调用WeChatPay微信服务--退款失败", userId, orders.getNumber());
                throw new OrderBusinessException(MessageConstant.ORDER_REFUND_ERROR);
            }
        }
        // 设置用户取消订单的状态、原因、时间
        updateOrder.setStatus(Orders.CANCELLED); //status=6 取消
        updateOrder.setCancelReason("用户取消");
        updateOrder.setCancelTime(LocalDateTime.now());
        // 5.修改订单信息
        Integer count = orderMapper.updateById(updateOrder);
        log.info("订单id: {},取消订单,影响行数: {}", id, count);
    }



    /**
     * 订单管理
     *        再来一单
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)  //开启事务  多表操作
    public void repeatOrder(Long id) {

        // 1.获取userId
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());
        // 2.将购物车数据清空  ---拓展：小程序已经调用过 "/user/shopCart/clean"接口了，此处可以不做这一步
        shoppingCartService.deleteUserShopCart(userId);

        // 3.根据 订单id和userId 查询订单
        Orders paramsOrder = Orders.builder().id(id).userId(userId).build();
        Orders order = orderMapper.getOrderByIdAndUserId(paramsOrder);
        // 4.校验订单
        if(Objects.isNull(order)){
            throw new OrderBusinessException(MessageConstant.ORDER_DATA_IS_NULL);
        }
        // 5.查询订单明细列表
        List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailListByOrderId(order.getId());
        // 6.校验订单明细
        if(CollectionUtils.isEmpty(orderDetailList)){
            throw new OrderBusinessException(MessageConstant.ORDER_DETAIL_IS_NULL);
        }

        // 7.遍历订单明细集合
        for (OrderDetail orderDetail : orderDetailList) {
            // 创建购物车对象
            ShoppingCart shoppingCart = new ShoppingCart();
            // 赋值
            shoppingCart.setName(orderDetail.getName());
            shoppingCart.setImage(orderDetail.getImage());
            shoppingCart.setUserId(userId);
            //菜品id不为空
            if(Objects.nonNull(orderDetail.getDishId())){
                shoppingCart.setDishId(orderDetail.getDishId());
                shoppingCart.setDishFlavor(orderDetail.getDishFlavor());
            }
            //套餐id不为空
            if(Objects.nonNull(orderDetail.getSetmealId())){
                shoppingCart.setSetmealId(orderDetail.getSetmealId());
            }
            shoppingCart.setNumber(orderDetail.getNumber());
            shoppingCart.setAmount(orderDetail.getAmount());
            shoppingCart.setCreateTime(LocalDateTime.now());

            //插入购物车
            shoppingCartService.addUserShoppingCart(shoppingCart);
        }

    }



    /**
     * 订单管理
     *        用户催单(发送Http请求到商家后台服务，调用WebSocket服务通知商家)
     * @param id
     */
    @Override
    public JSONObject userReminderOrder(Long id) {
        // 返回结果
        JSONObject result = new JSONObject();

        // 1.查询订单
        Long userId = Long.valueOf(AlibabaTTL.threadLocalGet().toString());
        Orders paramsOrders = Orders.builder().id(id).userId(userId).build();
        Orders orders = orderMapper.getOrderByIdAndUserId(paramsOrders);
        // 2.检验
        if(Objects.isNull(orders)){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        // TODO WebSocket服务
        /** 调用商户管理端后台，发送催单通知  **/
        Map<String, String> map = new HashMap<>();
        map.put("type", "2");                               // 通知类型 1表示来单提醒  2表示用户催单
        map.put("orderId", String.valueOf(orders.getId())); // 订单id
        map.put("content", "订单号:" + orders.getNumber());  // 订单号

        //返回结果
        String resultStr = null;

        //发送HTTP请求
        try {
            resultStr  = HttpClientUtil.doPostJsonHasParamsResponseJson(shopReminderUrl, map);
            //           {"code":1,"msg":null,"data":null}
            log.info("调用商家后台【催单服务】,响应结果: ", resultStr);
            if(StringUtils.hasLength(resultStr)){
                JSONObject data = JSONObject.parseObject(resultStr);
                if(Objects.nonNull(data) && data.getInteger("code") == 1){
                    result.put("code", data.getInteger("code"));
                    result.put("msg", data.getString("msg"));
                } else {
                    result = data;
                }
            }
        } catch (Exception e) {
            log.info("调用商家后台【催单服务】,抛出异常: ", e.getMessage());
            e.printStackTrace();
        }

        return result;
    }


}
